// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包驱动程序定义数据库要实现的接口
// 包sql使用的驱动程序。
// 
// 大多数代码都应该使用sql包。
// 
// 驱动程序接口随着时间的推移而不断发展。驱动程序应该实现
// 连接器和DriverContext接口。
// 连接器。连接和驱动程序。Open方法永远不应该返回ErrBadConn。
// 如果连接已经处于无效（例如关闭）状态，则只能从验证程序、会话重置程序或
// 查询方法返回ErrBadConn。
// 
// 所有Conn实现都应该实现以下接口：
// Pinger、sessionreseter和Validator。
// 
// 如果支持命名参数或上下文，则驱动程序的Conn应实现：
// ExecuteContext、QueryContext、ConnPareEconText和ConnBeginTx。
// 
// 要支持自定义数据类型，请实现NamedValueChecker。NamedValueChecker 
// 还允许查询通过返回
// ErrRemoveArgument from CheckNamedValue接受每个查询选项作为参数。
// 
// 如果支持多个结果集，则行应实现RowsNextResultSet。
// 如果驱动程序知道如何描述返回结果中存在的类型
// 它应该实现以下接口：RowsColumnTypeScanType，
// RowsColumnTypeDatabaseTypeName，RowsColumnTypeLength，RowsColumnTypeNullable，
// 和RowsColumnTypePrecisionScale。给定的行值还可能返回行
// 类型，该类型可能表示数据库游标值。
// 
// 在连接使用后返回到连接池之前，如果实现，则调用IsValid是
// 的。在将一个连接重新用于另一个查询之前，如果实现了，将调用
// ResetSession。如果一个连接从未返回到
// 连接池，但立即被重用，则在
// 重用之前调用ResetSession，但不调用IsValid。
package driver

import (
	"context"
	"errors"
	"reflect"
)

// 值是驱动程序必须能够处理的值。
// 它要么是nil，由数据库驱动程序的NamedValueChecker 
// 接口处理的类型，要么是其中一种类型的实例：
// 
// int64 
// float64 
// bool 
// []字节
// 字符串
// 时间。时间
// 
// 如果驱动程序支持游标，则返回值也可能实现此包中的行接口
// 。例如，当用户选择一个游标
// 例如“从dual中选择游标（从my_表中选择*）”时，就会使用这个选项。如果select中的行
// 关闭，光标行也将关闭。
type Value any

// NamedValue同时保存值name和value。
type NamedValue struct {
	// 如果名称不为空，则应将其用作参数标识符，而不是序号位置。
	// 
	// 名称将不会有符号前缀。
	Name string

	// 参数的顺序位置从一开始，始终设置。
	Ordinal int

	// 值是参数值。
	Value Value
}

// 驱动程序是必须由数据库
// 驱动程序实现的接口。
// 
// 数据库驱动程序可以实现DriverContext来访问上下文
// 并对连接池只解析一次名称，而不是每个连接一次。
type Driver interface {
	// Open返回到数据库的新连接。
	// 名称是一个特定于驱动程序格式的字符串。
	// 
	// Open可能会返回一个缓存连接（一个以前的
	// closed），但这样做是不必要的；sql包
	// 维护一个空闲连接池，以便高效重用。
	// 
	// 返回的连接一次只被一个goroutine使用。
	Open(name string) (Conn, error)
}

// 如果驱动程序实现DriverContext，那么sql。DB将调用
// OpenConnector来获取一个连接器，然后调用
// 该连接器的Connect方法来获取每个所需的连接，而不是调用驱动程序对每个连接的Open方法。
// 两步序列允许驱动程序只解析一次名称
// 还提供对每个连接上下文的访问。
type DriverContext interface {
	// OpenConnector必须以与驱动程序相同的格式解析名称。Open 
	// 解析name参数。
	OpenConnector(name string) (Connector, error)
}

// 连接器代表固定配置中的驱动程序
// 并且可以创建任意数量的等效连接器，供多个Goroutine使用
// 连接器。
// 
// 可以将连接器传递给sql。OpenDB，允许驱动程序
// 实现自己的sql。DB构造函数，或由
// DriverContext的OpenConnector方法返回，以允许驱动程序
// 访问上下文，并避免重复解析驱动程序
// 配置。
// 
// 如果连接器实现io。更接近sql包的数据库。Close 
// 方法将调用Close并返回错误（如果有）。
type Connector interface {
	// Connect返回到数据库的连接。
	// Connect可能会返回缓存的连接（之前的一个
	// closed），但这样做是不必要的；sql包
	// 维护一个空闲连接池，以便高效重用。
	// 
	// 提供的上下文。上下文仅用于拨号目的
	// （参见net.DialContext），不应存储或用于
	// 其他目的。拨号时仍应使用默认超时
	// 因为连接池可以异步调用Connect 
	// 来进行任何查询。
	// 
	// 返回的连接一次只被一个goroutine使用。
	Connect(context.Context) (Conn, error)

	// Driver返回连接器的底层驱动程序，
	// 主要是为了保持与sql上的驱动程序方法
	// 的兼容性。DB。
	Driver() Driver
}

// 一些可选接口的方法可能会将ErrSkip返回到
// 在运行时指出快速路径不可用，并且sql 
// 包应该继续，就像可选接口没有实现一样。只有明确记录了
// 时，才支持ErrSkip。
var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")

// 驱动程序应该返回ErrBadConn，以向sql 
// 程序包发送信号，表明驱动程序。Conn处于错误状态（例如服务器
// 之前已关闭连接），sql包应
// 重试新连接。
// 
// 为防止重复操作，如果数据库服务器可能执行了
// 操作，则不应返回ErrBadConn。即使服务器发回一个错误，
// 您也不应该返回ErrBadConn。
// 
// 将使用错误检查错误。是错误可能是
// 包装ErrBadConn或实现Is（error）bool方法。
var ErrBadConn = errors.New("driver: bad connection")

// Pinger是一个可选接口，可由Conn实现。
// 
// 如果Conn未实现Pinger，则sql包的数据库。Ping和
// DB。PingContext将检查是否至少有一个Conn可用。
// 
// 如果连接Ping返回ErrBadConn，DB。Ping和DB。PingContext将从池中删除
// Conn。
type Pinger interface {
	Ping(ctx context.Context) error
}

// Execer是一个可选接口，可由Conn实现。
// 
// 如果Conn既不实现ExecerContext也不实现Execer，
// sql包的数据库。Exec将首先准备一个查询，执行语句
// 然后关闭该语句。
// 
// Exec可能返回ErrSkip。
// 
// 已弃用：驱动程序应改为实现ExecContext。
type Execer interface {
	Exec(query string, args []Value) (Result, error)
}

// ExecerContext是一个可选接口，可由Conn实现。
// 
// 如果Conn未实现ExecerContext，则sql包的数据库。Exec 
// 将退回Exec；如果Conn也没有实现Execer，则
// DB。Exec将首先准备一个查询，执行该语句，然后
// 关闭该语句。
// 
// ExecerContext可能返回ErrSkip。
// 
// ExecerContext必须遵守上下文超时，并在取消上下文时返回。
type ExecerContext interface {
	ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
}

// Queryer是一个可选接口，可由Conn实现。
// 
// 如果Conn既不实现QueryContext也不实现Queryer，
// sql包的数据库。Query将首先准备一个查询，执行语句
// 然后关闭该语句。
// 
// 查询可能返回ErrSkip。
// 
// 已弃用：驱动程序应改为实现QueryContext。
type Queryer interface {
	Query(query string, args []Value) (Rows, error)
}

// QueryerContext是一个可选接口，可由Conn实现。
// 
// 如果Conn未实现QueryerContext，则sql包的数据库。查询
// 将返回到Queryer；如果Conn也没有实现Queryer，
// DB。Query将首先准备一个查询，执行该语句，然后
// 关闭该语句。
// 
// QueryerContext可能返回ErrSkip。
// 
// QueryerContext必须遵守上下文超时，并在取消上下文时返回。
type QueryerContext interface {
	QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
}

// Conn是与数据库的连接。多个goroutine不能同时使用
// 。
// 
// Conn被认为是有状态的。
type Conn interface {
	// Prepare返回绑定到此连接的已准备好的语句。
	Prepare(query string) (Stmt, error)

	// 关闭将使任何当前
	// 准备好的语句和事务失效并可能停止，并将此
	// 连接标记为不再使用。
	// 
	// 因为sql包维护一个免费的
	// 连接池，并且只有在剩余的
	// 空闲连接时才会关闭调用，所以驱动程序不必自己进行连接缓存。
	// 
	// 驱动程序必须确保关闭
	// 发出的所有网络呼叫不会无限期阻塞（例如应用超时）。
	Close() error

	// 开始并返回一个新事务。
	// 
	// 已弃用：驱动程序应改为（或另外）实现ConnBeginTx。
	Begin() (Tx, error)
}

// ConnPareContext增强了Conn与上下文的接口。
type ConnPrepareContext interface {
	// PrepareContext返回绑定到此连接的已准备好的语句。
	// 上下文用于准备语句，
	// 不能将上下文存储在语句本身中。
	PrepareContext(ctx context.Context, query string) (Stmt, error)
}

// IsolationLevel是存储在TxOptions中的事务隔离级别。
// 
// 此类型应被视为与sql相同。沿着
// 的隔离级别，上面定义了任何值。
type IsolationLevel int

// TxOptions持有交易选项。
// 
// 应将此类型视为与sql相同。TXO选项。
type TxOptions struct {
	Isolation IsolationLevel
	ReadOnly  bool
}

// ConnBeginTx通过上下文和TxOptions增强了Conn接口。
type ConnBeginTx interface {
	// BeginTx启动并返回一个新事务。
	// 如果用户取消了上下文，sql包将在放弃和关闭连接之前调用Tx.Rollback。
	// 
	// 这必须检查选项。隔离，以确定是否设置了
	// 隔离级别。如果驱动程序不支持非默认
	// 级别，并且设置了一个，或者如果存在不支持的非默认隔离级别
	// ，则必须返回错误。
	// 
	// 这还必须检查选项。ReadOnly，确定只读
	// 值是否为真，如果支持
	// 则设置只读事务属性，如果不支持则返回错误。
	BeginTx(ctx context.Context, opts TxOptions) (Tx, error)
}

// 会话重置器可由Conn实现，以允许驱动程序重置与连接相关的
// 会话状态，并发出连接不良的信号。
type SessionResetter interface {
	// 在对连接执行查询之前调用ResetSession 
	// 如果之前使用过该连接。如果驱动程序返回ErrBadConn 
	// 连接将被丢弃。
	ResetSession(ctx context.Context) error
}

// Conn可能会实现验证器，以允许驱动程序发出信号
// 指示连接是否有效或是否应该放弃连接。
// 
// 如果实现，驱动程序可能会从查询返回基本错误，
// 即使连接池应该丢弃连接。
type Validator interface {
	// 在将连接放入
	// 连接池之前调用IsValid。如果返回false，连接将被丢弃。
	IsValid() bool
}

// 结果是查询执行的结果。
type Result interface {
	// LastInsertId返回数据库自动生成的ID 
	// 例如，在使用主
	// 键插入表之后。返回受
	LastInsertId() (int64, error)

	// 查询影响的行数。
	RowsAffected() (int64, error)
}

// Stmt是一份事先准备好的声明。它与Conn有关，而不是
// 由多个goroutine同时使用。
type Stmt interface {
	// Close结束语句。
	// 
	// 从Go 1.1开始，如果Stmt被任何查询使用，它将不会被关闭。
	// 
	// 驱动程序必须确保关闭
	// 发出的所有网络呼叫不会无限期阻塞（例如，应用超时）。
	Close() error

	// NumInput返回占位符参数的数量。
	// 
	// 如果NumInput返回>=0，则在调用语句的Exec或查询方法之前，sql包将检查调用方的参数计数并向调用方返回错误。
	// 
	// NumInput也可能返回-1，如果驱动程序不知道它的占位符数。在这种情况下，sql包
	// 将不会对Exec或查询参数计数进行健全检查。
	NumInput() int

	// Exec执行一个不返回行的查询，例如
	// 作为插入或更新。
	// 
	// 已弃用：驱动程序应改为（或另外）实现StmtExecContext。
	Exec(args []Value) (Result, error)

	// 查询执行可能返回行的查询，例如
	// SELECT。
	// 
	// 已弃用：驱动程序应改为（或另外）实现StmtQueryContext。
	Query(args []Value) (Rows, error)
}

// STMTEXCEContext通过为Exec提供上下文来增强Stmt接口。
type StmtExecContext interface {
	// ExecContext执行一个不返回行的查询，例如
	// 作为插入或更新。
	// 
	// ExecContext必须遵守上下文超时并在取消时返回。
	ExecContext(ctx context.Context, args []NamedValue) (Result, error)
}

// StmtQueryContext通过提供上下文查询来增强Stmt接口。
type StmtQueryContext interface {
	// QueryContext执行可能返回行的查询，例如
	// SELECT。
	// 
	// QueryContext必须遵守上下文超时并在取消时返回。
	QueryContext(ctx context.Context, args []NamedValue) (Rows, error)
}

// 可以从NamedValueChecker返回ErrRemoveArgument，以指示
// sql包不将参数传递给驱动程序查询接口。
// 接受非
// SQL查询参数的查询特定选项或结构时返回。
var ErrRemoveArgument = errors.New("driver: remove argument from query")

// NamedValueChecker可以选择由Conn或Stmt实现。除了默认的
// 允许的值类型之外，它还为驱动程序提供了更多的控制来处理Go和数据库类型。
// 
// sql包按以下顺序检查值检查器，
// 在找到的第一个匹配项处停止：Stmt。NamedValueChecker，Conn.NamedValueChecker，
// Stmt。ColumnConverter，DefaultParameterConverter。
// 
// 如果CheckNamedValue返回ErrRemoveArgument，则NamedValue将不包含在
// 最终查询参数中。这可能用于将特殊选项传递给
// 查询本身。
// 
// 如果返回ErrSkip，则列转换器错误检查
// 路径用于参数。驾驶员可能希望在
// /他们已经用尽了自己的特殊情况后返回ErrSkip。
type NamedValueChecker interface {
	// 在将参数传递给驱动程序
	// 之前调用CheckNamedValue，并代替任何列转换器进行调用。CheckNamedValue必须执行
	// 类型的验证和转换，以适合驱动程序。
	CheckNamedValue(*NamedValue) error
}

// 如果
// 语句知道自己的列的类型，并且可以从
// 任何类型转换为驱动程序值，则可以选择由Stmt实现ColumnConverter。
// 
// 已弃用：驱动程序应实现NamedValueChecker。
type ColumnConverter interface {
	// ColumnConverter为提供的
	// 列索引返回一个ValueConverter。如果特定列的类型未知或不应进行特殊处理，则可以返回DefaultValueConverter 
	// 。
	ColumnConverter(idx int) ValueConverter
}

// 行是对已执行查询结果的迭代器。
type Rows interface {
	// Columns返回列的名称。根据
	// 列数。如果某个特定的列名未知，则应为该条目返回一个空的
	// 切片的长度推断出结果的
	// 字符串。
	Columns() []string

	// 关闭行迭代器。
	Close() error

	// 调用Next将下一行数据填充到提供的切片中。提供的切片大小将与列（）的宽度相同。
	// 
	// 下一步应该返回io。当没有更多行时执行EOF。
	// 
	// 不应将dest写入下一个之外的目录。关闭行时要小心，不要修改dest中的缓冲区。
	Next(dest []Value) error
}

// RowsNextResultSet通过提供一种方法来向驱动程序发送信号，使其前进到下一个结果集，从而扩展了Rows接口。
type RowsNextResultSet interface {
	Rows

	// 在当前结果集的末尾调用HasNextResultSet，并且
	// 报告当前结果集之后是否还有另一个结果集。
	HasNextResultSet() bool

	// NextResultSet将驱动程序推进到下一个结果集，如果当前结果集中还有剩余的行，甚至是
	// 。
	// 
	// NextResultSet应返回io。没有更多结果集时的EOF。
	NextResultSet() error
}

// RowsColumnTypeScanType可以按行实现。它应该返回
// 可用于将类型扫描到的值类型。例如，数据库
// 列类型“bigint”，它应该返回“reflect.TypeOf（int64（0））”。
type RowsColumnTypeScanType interface {
	Rows
	ColumnTypeScanType(index int) reflect.Type
}

// RowsColumnTypeDatabaseTypeName可以按行实现。它应该返回
// 数据库系统类型名称，不带长度。类型名称应为大写。
// 返回类型的示例：“VARCHAR”、“NVARCHAR”、“VARCHAR2”、“CHAR”、“TEXT”、
// /“DECIMAL”、“SMALLINT”、“INT”、“BIGINT”、“BOOL”、“[]BIGINT”、“JSONB”、“XML”、
type RowsColumnTypeDatabaseTypeName interface {
	Rows
	ColumnTypeDatabaseTypeName(index int) string
}

// RowsColumnTypeLength可以按行实现。如果列是可变长度类型，则应返回列类型的长度
// 。如果列为
// 不是可变长度类型，则ok应返回false。
// 如果长度不受系统限制之外的限制，则应返回数学。MaxInt64。
// 以下是各种类型返回值的示例：
// TEXT（math.MaxInt64，true）
// varchar（10）（10，true）
// nvarchar（10）（10，true）
// 十进制（0，false）
// int（0，false）
// bytea（30）（30，true）
type RowsColumnTypeLength interface {
	Rows
	ColumnTypeLength(index int) (length int64, ok bool)
}

// 如果列的可空性未知，则ok应为false。
type RowsColumnTypeNullable interface {
	Rows
	ColumnTypeNullable(index int) (nullable, ok bool)
}

// 行ColumnTypePrecisionScale可以按行实现。它应该返回
// 十进制类型的精度和小数位数。如果不适用，ok应为false。
// 以下是各种类型返回值的示例：
// 十进制（38,4）（38,4，true）
// int（0,0，false）
// 十进制（math.MaxInt64，math.MaxInt64，true）
type RowsColumnTypePrecisionScale interface {
	Rows
	ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool)
}

// Tx是一个事务。
type Tx interface {
	Commit() error
	Rollback() error
}

// RowsAffected为插入或更新操作实现结果
// 该操作会对多行进行变异。
type RowsAffected int64

var _ Result = RowsAffected(0)

func (RowsAffected) LastInsertId() (int64, error) {
	return 0, errors.New("LastInsertId is not supported by this driver")
}

func (v RowsAffected) RowsAffected() (int64, error) {
	return int64(v), nil
}

// resultnorws是一个预定义的结果，当DDL 
// 命令（如CREATE TABLE）成功时，驱动程序将返回该结果。它为
// LastInsertId和RowsAffected返回一个错误。
var ResultNoRows noRows

type noRows struct{}

var _ Result = noRows{}

func (noRows) LastInsertId() (int64, error) {
	return 0, errors.New("no LastInsertId available after DDL statement")
}

func (noRows) RowsAffected() (int64, error) {
	return 0, errors.New("no RowsAffected available after DDL statement")
}
